package service

import (
	"encoding/json"
	"errors"
	"gin_gorm_oj/define"
	"gin_gorm_oj/help"
	"gin_gorm_oj/modles"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"log"
	"net/http"
	"strconv"
)

// GetProblemList
// @Summary 问题列表
// @Tags 公共方法
// @Param size query int false "size"
// @Param page query int false "page"
// @Param keyword query string false "keyword"
// @Param category_identity query string false "category_identity"
// @Success 200 {string} json "{"code":"200","msg","","data":""}"
// @Router /problem-list [get]
func GetProblemList(c *gin.Context) {
	page, _ := strconv.Atoi(c.DefaultQuery("page", define.DefaultPage))
	size, _ := strconv.Atoi(c.DefaultQuery("size", define.DefaultSize))
	categoryIdentity := c.Query("category_identity")
	page = (page - 1) * size
	var count int64
	keyword := c.Query("keyword")

	data := make([]*modles.Problem, 0)
	tx := modles.GetProblemList(keyword, categoryIdentity)
	err := tx.Count(&count).Offset(page).Limit(size).Find(&data).Error
	if err != nil {
		log.Panicln("Problem Error:", err)
		return
	}
	c.String(http.StatusOK, "ok")

	c.JSON(200, gin.H{
		"code":  200,
		"msg":   data,
		"count": count,
	})

}

// GetProblemDetail
// @Tags 公共方法
// @Summary 问题详情
// @Param identity query string false "problem identity"
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /problem-detail [get]
func GetProblemDetail(c *gin.Context) {
	identity := c.Query("identity")
	if identity == "" {
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "问题标识不能为空",
		})
		return
	}
	problem := new(modles.Problem)
	err := modles.DB.Where("identity=?", identity).Preload("ProblemCategories.Category").First(&problem).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			c.JSON(200, gin.H{
				"code": -1,
				"msg":  "问题不存在",
			})
			return
		}
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "Get Error" + err.Error(),
		})
		return
	}
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  problem,
	})
}

// ProblemCreate
// @Tags 管理员私有方法
// @Summary 创建问题
// @Param authorization header string true "authorization"
// @Param title formData string true "title"
// @Param content formData string true "content"
// @Param category_ids formData array false "category_ids"
// @Param test_cases formData array false "test_cases"
// @Param max_runtime formData string true "max_runtime"
// @Param max_mem formData string true "max_mem"
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /problem-create [post]
func ProblemCreate(c *gin.Context) {
	title := c.PostForm("title")
	content := c.PostForm("content")
	maxRuntime, _ := strconv.Atoi(c.PostForm("max_runtime"))
	maxMem, _ := strconv.Atoi(c.PostForm("max_mem"))
	categoryIds := c.PostFormArray("category_ids")
	testCases := c.PostFormArray("test_cases")
	if title == "" || content == "" || maxRuntime <= 0 || maxMem <= 0 || len(categoryIds) == 0 || len(testCases) == 0 {
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "参数为空或错误",
		})
		return
	}
	identity := help.GetUUID()
	data := &modles.Problem{
		Identity:   identity,
		Title:      title,
		Content:    content,
		MaxRuntime: maxRuntime,
		MaxMem:     maxMem,
	}

	//处理分类
	categoryBasics := make([]*modles.ProblemCategory, 0)
	for _, id := range categoryIds {
		categoryId, _ := strconv.Atoi(id)
		categoryBasics = append(categoryBasics, &modles.ProblemCategory{
			ProblemId:  data.ID,
			CategoryId: uint(categoryId),
		})
	}
	data.ProblemCategories = categoryBasics

	//处理测试案例
	testCaseBasics := make([]*modles.TestCase, 0)
	for _, testCase := range testCases {
		caseMap := make(map[string]string)
		err := json.Unmarshal([]byte(testCase), &caseMap)
		if err != nil {
			c.JSON(200, gin.H{
				"code": -1,
				"msg":  "测试案例格式错误",
			})
			return
		}
		if _, ok := caseMap["input"]; !ok {
			c.JSON(200, gin.H{
				"code": -1,
				"msg":  "测试案例为空",
			})
			return
		}
		if _, ok := caseMap["output"]; !ok {
			c.JSON(200, gin.H{
				"code": -1,
				"msg":  "测试案例为空",
			})
			return
		}
		testCaseBasic := &modles.TestCase{
			Identity:        help.GetUUID(),
			ProblemIdentity: identity,
			Input:           caseMap["input"],
			Output:          caseMap["output"],
		}
		testCaseBasics = append(testCaseBasics, testCaseBasic)

	}
	data.TestCases = testCaseBasics

	//创建问题
	err := modles.DB.Create(data).Error
	if err != nil {
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "Create Error" + err.Error(),
		})
		return
	}

	c.JSON(200, gin.H{
		"code": 200,
		"msg":  identity,
	})

}

// ProblemUpdate
// @Tags 管理员私有方法
// @Summary 修改问题
// @Param authorization header string true "authorization"
// @Param identity formData string true "identity"
// @Param title formData string true "title"
// @Param content formData string true "content"
// @Param category_ids formData []string false "category_ids" collectionFormat(multi)
// @Param test_cases formData []string false "test_cases" collectionFormat(multi)
// @Param max_runtime formData string true "max_runtime"
// @Param max_mem formData string true "max_mem"
// @Success 200 {string} json "{"code":"200","data":""}"
// @Router /problem-update [put]
func ProblemUpdate(c *gin.Context) {
	identity := c.PostForm("identity")
	title := c.PostForm("title")
	content := c.PostForm("content")
	maxRuntime, _ := strconv.Atoi(c.PostForm("max_runtime"))
	maxMem, _ := strconv.Atoi(c.PostForm("max_mem"))
	categoryIds := c.PostFormArray("category_ids")
	testCases := c.PostFormArray("test_cases")
	if title == "" || content == "" || maxRuntime <= 0 || maxMem <= 0 || len(categoryIds) == 0 || len(testCases) == 0 {
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "参数为空或错误",
		})
		return
	}

	//事务回滚
	if err := modles.DB.Transaction(func(tx *gorm.DB) error {
		problem := &modles.Problem{
			Identity:   identity,
			Title:      title,
			Content:    content,
			MaxRuntime: maxRuntime,
			MaxMem:     maxMem,
		}
		err1 := tx.Where("identity=?", identity).Updates(problem).Error
		if err1 != nil {
			return err1
		}
		//查询问题
		err2 := tx.Where("identity=?", identity).Find(problem).Error
		if err2 != nil {
			return err2
		}
		//分类的更新
		//1,删除存在的关联关系
		err3 := tx.Where("problem_id=?", problem.ID).Delete(new(modles.ProblemCategory)).Error
		if err3 != nil {
			return err3
		}
		//新增分类关系
		psc := make([]*modles.ProblemCategory, 0)
		for _, id := range categoryIds {
			id, _ := strconv.Atoi(id)
			psc = append(psc, &modles.ProblemCategory{
				ProblemId:  problem.ID,
				CategoryId: uint(id),
			})
		}
		err4 := tx.Create(&psc).Error
		if err4 != nil {
			return err4
		}
		//测试案例更新
		//1.删除测试案例
		err5 := tx.Where("problem_identity=?", identity).Delete(new(modles.TestCase)).Error
		if err5 != nil {
			return err1
		}
		//2.新增测试案例
		tsc := make([]*modles.TestCase, 0)
		for _, testCase := range testCases {

			caseMap := make(map[string]string)
			err6 := json.Unmarshal([]byte(testCase), &caseMap)
			if err6 != nil {
				return err6
			}
			if _, ok := caseMap["input"]; !ok {
				return errors.New("测试案例输入为空")
			}
			if _, ok := caseMap["output"]; !ok {
				return errors.New("测试案例输出为空")
			}
			tsc = append(tsc, &modles.TestCase{
				Identity:        help.GetUUID(),
				ProblemIdentity: identity,
				Input:           caseMap["input"],
				Output:          caseMap["output"],
			})
		}
		err7 := tx.Create(&tsc).Error
		if err7 != nil {
			return err7
		}
		return nil
	}); err != nil {
		c.JSON(200, gin.H{
			"code": -1,
			"msg":  "更新问题错误" + err.Error(),
		})
		return
	}
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "更新成功",
	})
}
